package se.webbzon.oschi01.stream;

import java.io.DataInput;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

public class LittleEndianDataInputStream extends FilterInputStream implements DataInput {

	private final Charset utf8 = StandardCharsets.UTF_8;
	
	private final byte[] w;
	
	/*============================================================
	Constructors
	============================================================*/
	
	public LittleEndianDataInputStream(InputStream is) {
		super(is);
		w = new byte[8];
	}
	
	/*============================================================
	Public Methods
	============================================================*/

	@Override public boolean readBoolean() throws IOException {
		return in.read() != 0;
	}

	@Override public byte readByte() throws IOException {
		return (byte) in.read();
	}

	@Override public char readChar() throws IOException {
		readFully(w,0,2);
		return (char) ((w[1] << 8) | (w[0] & 0xff));
	}

	@Override public double readDouble() throws IOException {
		return Double.longBitsToDouble(readLong());
	}

	@Override public float readFloat() throws IOException {
		return Float.intBitsToFloat(readInt());
	}

	@Override public void readFully(byte[] b) throws IOException {
		readFully(b, 0, b.length);
	}

	@Override public void readFully(byte[] b, int off, int len) throws IOException {
		while (in.available() < len);
		in.read(b, off, len);
	}

	@Override public int readInt() throws IOException {
		readFully(w,0,4);
		return	(w[3] & 0xff)	<< 24 |
				(w[2] & 0xff)	<< 16 |
				(w[1] & 0xff)	<<  8 |
				(w[0] & 0xff);
	}

	@Override public String readLine() throws IOException {
		StringBuilder builder = new StringBuilder();
		while (true) {
			char c = readChar();
			if (c == '\n')
				return builder.toString();
			else if (c == '\r') {
				readChar();
				return builder.toString();
			} else
				builder.append(c);
		}
	}

	@Override public long readLong() throws IOException {
		readFully(w,0,8);
		return	(long) (w[7])      		<< 56 | 
				(long) (w[6] & 0xff)	<< 48 |
				(long) (w[5] & 0xff)	<< 40 |
				(long) (w[4] & 0xff)	<< 32 |
				(long) (w[3] & 0xff)	<< 24 |
				(long) (w[2] & 0xff)	<< 16 |
				(long) (w[1] & 0xff)	<<  8 |
				(long) (w[0] & 0xff);
	}

	@Override public short readShort() throws IOException {
		readFully(w,0,2);
		return (short) ((w[1] << 8) | (w[0] & 0xff));
	}

	@Override public String readUTF() throws IOException {
		int length = readUnsignedShort();
		byte[] d = new byte[length];
		readFully(d,0,length);
		return new String(d,utf8);
	}

	@Override public int readUnsignedByte() throws IOException {
		return in.read();
	}

	@Override public int readUnsignedShort() throws IOException {
		readFully(w,0,2);
		return (w[1] << 8) | (w[0] & 0xff);
	}

	@Override public int skipBytes(int n) throws IOException {
		return (int) in.skip(n);
	}

}
